/*
 * @Author: hongbin
 * @Date: 2023-04-02 09:43:53
 * @LastEditors: hongbin
 * @LastEditTime: 2023-04-03 13:55:27
 * @Description:升降台
 */
import { ThreeHelper } from "@/src/ThreeHelper";
import { Vector3 } from "three";
import { usePrompt } from "./dom/Prompt";
import { getMeshTriangles } from "@/src/ThreeHelper/expand/Octree";
import {
    OctreeControls,
    OctreeResult,
} from "@/src/ThreeHelper/utils/OctreeControls";

interface IParams {
    obj: Mesh;
    move: (v: Vector3) => void;
    up: (v: Vector3) => void;
    helper?: Object3D;
}

export class LiftingPlatform {
    private initPosition = new Vector3();
    private upSpeed = new Vector3(0, -0.04, 0);
    private moveCount = 0;
    private moveTotal = 200;
    private params?: IParams;
    private prevRenderTime = performance.now();
    /** 按需计算 */
    private needCompute = false;
    translate!: (v: { x: number; y: number; z: number }) => void;
    private triangles!: any;
    /**
     * 人站在平台上下降
     */
    downing = false;

    constructor(params: IParams) {
        if (!params.obj) console.error("no obj or no box3!");
        else {
            this.params = params;
            // 计算三角面
            const { translate, triangles } = getMeshTriangles(params.obj);
            this.triangles = triangles;
            this.translate = translate;
            this.initPosition.copy(params.obj.position);
            this.params.obj.onBeforeRender = () => {
                this.needCompute = true;
                this.prevRenderTime = performance.now();
            };
            if (this.params.helper) {
                this.params.helper.onBeforeRender = () => {
                    this.needCompute = true;
                    this.prevRenderTime = performance.now();
                };
            }
            ThreeHelper.instance.keyBoardListen();
            ThreeHelper.instance.listenKey("KeyF", () => {
                if (!this.needCompute) return;
                // 显示按键才能执行
                if (!usePrompt.current?.isShow) return;
                if (this.moveCount === 0) {
                    usePrompt.current?.hide();
                    this.moveCount++;
                    // 先向反方向走一帧的距离 因为平台会先上升人后人上升 人的脚会陷进平台
                    params.up(this.upSpeed);
                    this.upSpeed.y *= -1;
                } else {
                    /** 重置平台 */
                    this.moveCount = 0;
                    const diff = new Vector3().subVectors(
                        this.initPosition,
                        this.params!.obj.position
                    );
                    this.upSpeed.y *= -1;
                    this.translate(diff);
                }
            });
        }
    }

    update(result: OctreeResult, octreeControls: OctreeControls) {
        if (!this.needCompute || !this.params) return;

        /** 如果距离上次渲染超过了1秒认为不需要进行计算了 已经离开升降台了 */
        if (performance.now() - this.prevRenderTime > 1000) {
            this.needCompute = false;
        }
        this.downing = false;
        // 八叉树检测时加上平台的三角面
        octreeControls.triangles = this.triangles;
        if (!result) return usePrompt.current?.hide();

        if (this.moveCount === 0) {
            if (result.meshNames!.includes(this.params.obj.name)) {
                const dir = this.upSpeed.y < 0 ? "上升" : "下降";
                usePrompt.current?.show(dir);
            } else usePrompt.current?.hide();
        } else {
            if (result.meshName === this.params.helper?.name) {
                usePrompt.current?.show("重置");
            } else usePrompt.current?.hide();
        }

        if (this.moveCount !== 0) {
            if (this.moveCount++ < this.moveTotal) {
                this.translate(this.upSpeed);
                // 站在平台上下降时
                if (
                    result.meshNames!.includes(this.params.obj.name) &&
                    this.upSpeed.y < 0
                ) {
                    this.params.move(this.upSpeed);
                    this.downing = true;
                }
            }
            // 结束运动 人不在平台上 平台落回下面
            else {
                this.moveCount = 0;
            }
        }
    }
}
